<script lang="tsx">
import { computed, defineComponent, onMounted, type PropType, ref, unref, watch } from 'vue'
import type { Recordable } from '../types/form'
import { cloneDeep, get, has, isArray, isFunction, isObject } from 'lodash-es'
import { useRuleFormItem } from '../common/useFormItem'
import { ElCascader } from 'element-plus'
import type { OptionsItem } from '../types/formItem'
import { propTypes } from '@/types/propTypes'
import { treeToOneArr } from '@/utils/Tree'

type ResOpj = { code: number; data: OptionsItem[] | null }

export default defineComponent({
  name: 'BasicFormApiCascader',
  props: {
    modelValue: {
      type: Array as PropType<string[] | number[]>,
    },
    modelName: {
      type: Array as PropType<string[]>,
    },
    api: {
      type: Function as PropType<(arg?: Recordable) => Promise<ResOpj>>,
      default: null,
    },
    // api params
    params: {
      type: Object as PropType<Recordable>,
      default: () => ({}),
    },
    //树形结构字段映射
    props: {
      type: Object as PropType<Recordable>,
      default: () => {
        return {
          children: 'children',
          label: 'label',
          value: 'id',
        }
      },
    },
    resultField: propTypes.string.def(''),
    // 自定义处理接口返回参数
    afterFetch: propTypes.func,
    // 是否显示完整的路径
    showAllLevels: propTypes.bool.def(true),
  },

  emit: ['update:modelValue', 'options-change', 'update:modelName'],

  setup(props, { emit, attrs, slots }) {
    const treeData = ref<OptionsItem[]>([])
    const [state] = useRuleFormItem(props, 'modelValue', 'update:modelValue')

    watch(
      () => props.params,
      () => {
        fetch()
      },
      { deep: true },
    )
    watch(
      () => state.value,
      (v) => {
        // console.log('vvvvv', v);
        if (v?.length == 0) {
          emit('update:modelName', [])
        } else {
          let aa = treeToOneArr(unref(treeData))
          let names = dataToString(v as number[] | [number[]], aa)
          // console.log('names', names);

          emit('update:modelName', names)
        }
      },
    )
    onMounted(() => {
      fetch()
    })
    const getBindValue = computed(() => {
      return { ...attrs, ...props }
    })
    const getOptions = computed(() => {
      const { props: propsd, afterFetch } = props
      if (isFunction(afterFetch)) {
        // eslint-disable-next-line vue/no-side-effects-in-computed-properties
        treeData.value = afterFetch(cloneDeep(unref(treeData)))
      }
      let optionArr = treeDataSeal(treeData.value, propsd)
      return optionArr
    })

    function dataToString(data: number[] | [number[]], dataArr: Recordable[]): string | string[] {
      let names: string[] = []
      let text = ''
      unref(data).forEach((one: number | number[], index: number) => {
        if (isArray(one)) {
          names.push(dataToString(one, dataArr) as string)
        } else {
          let oneFile: any = dataArr.filter((e: Recordable) => e.value == one)
          if (oneFile.length) {
            text += `${oneFile[0].label}${index != data.length - 1 ? '/' : ''}`
          }
        }
      })
      //   是否显示完整的路径 false 不显示
      if (!props.showAllLevels) {
        let lasindex = text.lastIndexOf('/')
        if (lasindex > -1) {
          text = text.slice(lasindex + 1, text.length)
        }
      }
      return text.length ? text : names
    }

    function treeDataSeal(
      res: any,
      propsd = {
        children: 'children',
        label: 'label',
        value: 'id',
      } as Recordable,
      keys?: string,
    ) {
      const dataArr: any[] = []
      isArray(res) &&
        res.forEach((e: any) => {
          e.label = e[propsd.label]
          e.value = e[propsd.value]
          e.key = keys ? keys + e[propsd.value] : e[propsd.value].toString()
          if (isArray(e[propsd.children]) && e[propsd.children].length) {
            e.children = treeDataSeal(e[propsd.children], propsd, e.key + '-')
          }
          dataArr.push(e)
        })
      return dataArr
    }

    async function fetch() {
      const api = props.api
      if (!api || !isFunction(api)) return
      treeData.value = []
      try {
        const res = await api(props.params)
        // console.log('res', res);
        if (isObject(res)) {
          if (has(res, 'code') && res.code != 0) {
            return console.error('数据错误')
          }
          if (isArray(res.data)) {
            treeData.value = res.data
            emitChange()
            return
          }
          //  a.b.c
          if (props.resultField) {
            treeData.value = get(res, props.resultField) || []
            emitChange()
          }
        }
        // 数组数据
        if (isArray(res)) {
          treeData.value = res
          emitChange()
          return
        }
      } catch (error) {
        console.warn(error)
      } finally {
      }
    }
    function emitChange() {
      emit('options-change', unref(getOptions))
    }
    return () => {
      return (
        <ElCascader
          {...getBindValue.value}
          modelValue={state.value}
          options={getOptions.value}
          class="w-[100%]"
        ></ElCascader>
      )
    }
  },
})
</script>
<style lang="scss" scoped></style>
